/*
 * @Description:mongo数据库接口
 * @Author: maskMan
 * @LastEditTime: 2024-01-26 19:10:10
 */
import { time } from "console";
import { MongoClient, Db, Collection, FindCursor } from "mongodb";
import { ISort, MonTable, MonUser, Obj } from "../config/type";
import { Monconf } from "../config/type";
import { util } from "../config/util";
export class Mondb {
  /**连接mongo数据库 */
  /**默认排序 */
  private static _sort: ISort = {
    dir: 1,
    key: null,
    limit: 9999999,
  };
  private static _client: MongoClient;
  private static _db: Db;
  private static _monUser: Collection;
  private static _monIncre: Collection;
  /**
   * @description: 删除集合如果为空则全部删除
   * @param {*} name 集合名字
   * @return {*}
   */
  private static async _delCollection(name?): Promise<boolean> {
    if (!name) {
      const list = await this._db.collections({ nameOnly: true });
      for (let i = 0; i < list.length; i++) {
        await this._db.dropCollection(list[i].collectionName);
      }
      return Promise.resolve(true);
    }
    return await this._db.dropCollection(name);
  }
  /**
   * @description: 转成成过滤字段
   * @return {*}
   */
  private static _changeToFilter(filter: any[], type?: 1 | 0): Obj {
    const filterList = {};
    filter.forEach((v) => {
      filterList[v] = type ? type : 1;
    });
    return filterList;
  }
  /**
   * @description: 游标转换为数据
   * @return {*}
   */
  private static async _curToData(findCur: FindCursor): Promise<any[]> {
    const resList = [];
    while (await findCur.hasNext()) {
      resList.push(await findCur.next());
    }
    return resList;
  }
  /**
   * @description: 查找指定集合集体
   * @return {*}
   */
  private static async _getSpecialCollection(name: string): Promise<Collection> {
    const list = await this._db.collections();
    for (let i = 0; i < list.length; i++) {
      if (list[i].collectionName == name) {
        return Promise.resolve(list[i]);
      }
    }
    return Promise.resolve(null);
  }
  /**
   * @description: 设置表索引
   * @return {*}
   */
  public static async _setMonIndex(...list): Promise<boolean> {
    try {
      const res = list.map((v) => {
        const obj = {
          key: {
            [v]: -1,
          },
          unique: true,
        };
        return obj;
      });
      await this._monUser.createIndexes(res);
      return true;
    } catch (error) {
      return false;
    }
  }
  /**
   * @description: 递增唯一键值
   * @return {*}
   */
  public static async _autoIncreKey(key: string): Promise<number> {
    try {
      if (!this._monIncre) {
        const item = await this._getSpecialCollection(MonTable.incre);
        this._monIncre = item == null ? await this._db.collection(MonTable.incre) : item;
      }
      const findRes = await this._monIncre.findOneAndUpdate(
        {
          [key]: { $exists: true },
        },
        {
          $setOnInsert: { [key]: true },
          $inc: { __value: 1 },
        },
        { upsert: true }
      );
      if (findRes == null) {
        await this._monIncre.insertOne({ __value: 1 });
        return Promise.resolve(1);
      }
      return Promise.resolve(findRes.__value);
    } catch (error) {
      console.log(error);
      return Promise.resolve(0);
    }
  }
  /**
   * @description: 创建连接池
   * @param {*} dblConf 数据库配置
   * @return {*}
   */
  public static async connectPool(conf: Monconf) {
    const url = `mongodb://${conf.user}:${conf.password}@127.0.0.1:27017/${conf.dbName}?authSource=admin`;
    this._client = await MongoClient.connect(url);
    this._db = this._client.db();
    return true;
  }
  /**
   * @description: 获取用户集合
   * @return {*}
   */
  public static async _getMonUser(): Promise<Collection> {
    try {
      if (!this._monUser) {
        const item = await this._getSpecialCollection(MonTable.user);
        if (item == null) {
          this._monUser = await this._db.collection(MonTable.user);
          await this._setMonIndex("openid", "uid");
          return this._monUser;
        }
        this._monUser = item;
      }
      return this._monUser;
    } catch (error) {
      console.log(error);
      return null;
    }
  }
  /**
   * @description: 插入一条用户到期
   * @param {MonUser} userData 插入数据
   * @param {Array} filter 过滤字段
   * @return {*} 速度 10000次/12714 s
   */
  public static async insertOneUser(userData: MonUser, filter?: Array<keyof MonUser>): Promise<MonUser> {
    try {
      const userMon = await this._getMonUser();
      if (userMon) {
        const filterData = filter ? this._changeToFilter(filter) : null;
        userData.uid = await this._autoIncreKey("uid");
        const first = {
          openid: userData.openid,
        };
        const upData = {
          $setOnInsert: userData,
        };
        const findRes = await userMon.findOneAndUpdate(first, upData, { upsert: true, projection: filterData });
        if (findRes == null) {
          userData.new = true;
          return userData;
        }
        return findRes as unknown as MonUser;
      }
    } catch (error) {
      console.log(error);
      return null;
    }
  }
  /**
   * @description: 根据ID查找一条信息
   * @param {string} uid 用户UID
   * @param {string} filter 过滤字段
   * @return {*}速度 10000次/7459 s
   */
  public static async findOneUserById(uid: number, filter?: Array<keyof MonUser>): Promise<MonUser> {
    try {
      const userMon = await this._getMonUser();
      if (userMon) {
        const filterData = filter ? this._changeToFilter(filter) : null;
        const res = { uid: { $eq: uid } };
        const findRes = await userMon.findOne(res, { projection: filterData });
        return findRes as unknown as MonUser;
      }
    } catch (error) {
      console.log(error);
      return null;
    }
  }
  /**
   * @description: 查找多条用户数据
   * @param {string} uidList 用户ID列表
   * @param {string} filter 过滤字段
   * @param {ISort} sort 排名信息
   * @return {*}速度 10000次/7459 s
   */
  public static async findManyUserById(uidList: number[], filter: Array<keyof MonUser> = [], sort?: ISort): Promise<MonUser[]> {
    try {
      const userMon = await this._getMonUser();
      if (userMon) {
        const filterData = filter ? this._changeToFilter(filter) : null;
        const sortData = sort == undefined ? this._sort : sort;
        const findCur = userMon
          .find({ uid: { $in: uidList } }, { projection: filterData })
          .sort(sortData.key, sortData.dir)
          .limit(uidList.length);
        const resList = await this._curToData(findCur);
        return resList as unknown as MonUser[];
      }
    } catch (error) {
      console.log(error);
      return [];
    }
  }
  /**
   * @description:根据ID更新指定用户信息
   * @param {string} uid 用户ID
   * @param {Obj} data 更新数据信息
   * @param {string} filter 过滤的字段
   * @return {*} 速度 10000次/5651 ms
   */
  public static async updateOneUserById(uid: number, updata: Obj, filter: Array<keyof MonUser> = []): Promise<MonUser> {
    try {
      const userMon = await this._getMonUser();
      if (userMon) {
        const filterData = filter ? this._changeToFilter(filter) : null;
        const findRes = userMon.findOneAndUpdate({ uid: { $eq: uid } }, { $set: updata }, { projection: filterData, returnDocument: "after" });
        return findRes as unknown as MonUser;
      }
    } catch (error) {
      console.log(error);
      return null;
    }
  }
  /**
   * @description: 超找一条数据
   * @param {Obj} ucondition 超找条件
   * @param {Array} filter 过滤字段
   * @return {*}速度 10000条/7683 ms
   */
  public static async findOneData<T extends any>(ucondition: Obj, filter?: Array<keyof T>): Promise<T> {
    try {
      const userMon = await this._getMonUser();
      if (userMon) {
        const filterData = filter ? this._changeToFilter(filter) : null;
        const findRes = await userMon.findOne(ucondition, { projection: filterData });
        return findRes as unknown as T;
      }
    } catch (error) {
      console.log(error);
      return null;
    }
  }
  /**
   * @description: 查找符合条件的所有数据列表并排名
   * @param {Obj} condition 查找条件
   * @param {string} filter   过滤的字段
   * @param {ISort} sort 排序信息
   * @return {*}速度 每查找 10000条信息/261 ms
   */
  public static async findAllData<T extends any>(condition: Obj, filter: Array<keyof T> = null, sort?: ISort): Promise<T[]> {
    try {
      const userMon = await this._getMonUser();
      if (userMon) {
        const sortData = sort == undefined ? this._sort : sort;
        const filterData = filter ? this._changeToFilter(filter) : null;
        const findCur = userMon.find(condition, { projection: filterData }).sort(null, sortData.dir).limit(sortData.limit);
        const resList = await this._curToData(findCur);
        return resList as unknown as T[];
      }
    } catch (error) {
      console.log(error);
      return [];
    }
  }
  /**
   * @description: 更新符合条件的一条数据
   * @param {Obj} condition 更新条件
   * @param {Obj} updata 更新数据
   * @return {*} 速度 10000次/5651 s
   */
  public static async updateOneData<T extends any>(condition: Obj, updata: Obj, filter?: Array<keyof T>): Promise<T> {
    try {
      const userMon = await this._getMonUser();
      if (userMon) {
        const filterData = filter ? this._changeToFilter(filter) : null;
        const findRes = await userMon.findOneAndUpdate(condition, { $set: updata }, { projection: filterData, returnDocument: "after" });
        return findRes as unknown as T;
      }
    } catch (error) {
      console.log(error);
      return null;
    }
  }
  /**
   * @description: 更新符合条件的多条数据
   * @param {Obj} condition 更新条件
   * @param {Obj} updata 更新数据
   * @return {*}速度 10000条/421 ms
   */
  public static async updateAllData(condition: Obj, updata: Obj): Promise<boolean> {
    try {
      const userMon = await this._getMonUser();
      if (userMon) {
        const findRes = await userMon.updateMany(condition, { $set: updata });
        return findRes.acknowledged ? true : false;
      }
    } catch (error) {
      console.log(error);
      return false;
    }
  }

  /**
   * @description: 插入一条数据
   * @param {T} allData 查找条件
   * @param {string} autoKey 自增序号key
   * @param {Array} filter 过滤字段
   * @return {*} 速度 10000条/12714 s
   */
  public static async insertOneData<T extends any>(createData: T, autoKey: string, filter?: Array<keyof T>): Promise<T> {
    try {
      const userMon = await this._getMonUser();
      if (userMon) {
        const filterData = filter ? this._changeToFilter(filter) : null;
        createData[autoKey] = await this._autoIncreKey(autoKey);
        const first = {
          [autoKey]: createData[autoKey],
        };
        const upData = {
          $setOnInsert: createData,
        };
        const findRes = await userMon.findOneAndUpdate(first, upData, { upsert: true, projection: filterData });
        if (findRes == null) {
          return createData;
        }
        return findRes as unknown as T;
      }
    } catch (error) {
      console.log(error);
      return null;
    }
  }
  /**
   * @description: 插入多条数据
   * @param {T} allData 数据数组
   * @param {string} autoKey 增长键
   * @return {*} 速度 10000次 1条/15406 s
   */
  public static async insertManyData<T>(createData: T[], autoKey: string): Promise<boolean> {
    try {
      const userMon = await this._getMonUser();
      if (userMon) {
        for (let i = 0; i < createData.length; i++) {
          createData[i][autoKey] = await this._autoIncreKey(autoKey);
        }
        const findRes = await userMon.insertMany(createData);
        return findRes.acknowledged ? true : false;
      }
    } catch (error) {
      console.log(error);
      return false;
    }
  }
}
